import mx.utils.Delegate;

import gugga.common.ITask;
import gugga.debug.Assertion;
import gugga.events.EventDispatcher;
import gugga.utils.OnEnterFrameBeacon;

/**
 * Task playing specified frames forward or backward.
 * 
 * Important Note: If we have more than one running FrameByFrameAnimation animations which are sharing same mMovieClip, 
 * then this class will have unexpected behavior. 
 * 
 * @author Stefan Yotov
 */
class gugga.animations.FrameByFrameAnimation 
	extends EventDispatcher implements ITask 
{
	private var mMovieClip : MovieClip;
	private var mStartFrame : Number;
	private var mTargetFrame : Number;
	
	private var mStartFromCurrentFrame :  Boolean = false;
	
	private var mIsRunning : Boolean = false;
	
	private var onEnterFrameDelegate : Function;
	
	/**
	 * "Overloaded" to be used with frame labels and/or frame numbers.
	 */
	public function FrameByFrameAnimation (aMovieClip : MovieClip, aEnd : Object, aStart : Object)
	{
		super();
		
		mMovieClip = aMovieClip;
		
		var currentFrame : Number = mMovieClip._currentframe;
		
		if(aStart == undefined)
		{
			mStartFrame = mMovieClip._currentframe;
			mStartFromCurrentFrame = true;
		}
		else if(!isNaN(Number(aStart)))
		{
			mStartFrame = Number(aStart);
		}
		else
		{
			mMovieClip.gotoAndStop(String(aStart));
			mStartFrame = mMovieClip._currentframe;
			mMovieClip.gotoAndStop(currentFrame);
		}
		
		if(!isNaN(Number(aEnd)))
		{
			mTargetFrame = Number(aEnd);
		}
		else
		{
			mMovieClip.gotoAndStop(String(aEnd));
			mTargetFrame = mMovieClip._currentframe;
			mMovieClip.gotoAndStop(currentFrame);
		}
		
		Assertion.warningIfFalse(
			mMovieClip._totalframes >= mTargetFrame && mMovieClip._totalframes >= mStartFrame && mStartFrame > 0 && mTargetFrame > 0,
			"Invalid arguments.",
			this, arguments);
		
		onEnterFrameDelegate = Delegate.create(this, onEnterFrameHandler);
	}
	
	public function start() : Void 
	{
		mIsRunning = true;
		OnEnterFrameBeacon.Instance.addEventListener("onEnterFrame", onEnterFrameDelegate);
		
		if(mStartFromCurrentFrame)
		{
			mStartFrame = mMovieClip._currentframe;
		}
		
		mMovieClip.gotoAndStop(mStartFrame);
		onEnterFrameHandler();
	}

	public function isRunning() : Boolean 
	{
		return mIsRunning;
	}

	public function isImmediatelyInterruptable() : Boolean 
	{
		return true;
	}

	public function interrupt() : Void 
	{
		OnEnterFrameBeacon.Instance.removeEventListener("onEnterFrame", onEnterFrameDelegate);
		mIsRunning = false;
		dispatchEvent({type:"interrupted", target:this});
	}
	
	private function onEnterFrameHandler () : Void
	{
		if(mMovieClip._currentframe < mTargetFrame)
		{
			mMovieClip.nextFrame();
		}
		else if(mMovieClip._currentframe > mTargetFrame)
		{
			mMovieClip.prevFrame();
		}
		
		if(mMovieClip._currentframe == mTargetFrame)
		{
			OnEnterFrameBeacon.Instance.removeEventListener("onEnterFrame", onEnterFrameDelegate);
			mIsRunning = false;
			dispatchEvent({type:"completed", target:this});
		}
	}
}